package com.huawei.aiservice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huawei.aiservice.entity.pojo.*;
import com.huawei.aiservice.entity.vo.*;
import com.huawei.aiservice.mapper.ReportMapper;
import com.huawei.aiservice.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {
    @Resource
    private FileEntityService fileEntityService;

    @Resource
    private RuleService ruleService;

    @Resource
    private FileRuleService fileRuleService;

    @Resource
    private DefectService defectService;
    public Response<Page<ReportVo>> getReportVo(String userId, int pageNum, int pageSize) {
        // 创建分页对象
        Page<Report> page = new Page<>(pageNum, pageSize);
        // 按时间倒序分页查询
        LambdaQueryWrapper<Report> wrapper = new LambdaQueryWrapper<Report>()
                .eq(Report::getUserId, userId)
                .orderByDesc(Report::getCreateTime);
        Page<Report> reportPage = baseMapper.selectPage(page, wrapper);
        Long total = baseMapper.selectCount(wrapper);

        //TODO user
        List<ReportVo> reportVoList = convertToReportVo(reportPage.getRecords(), "BeicC");

        Page<ReportVo> result = new Page<>();
        result.setRecords(reportVoList);
        result.setTotal(total);
        result.setSize(pageSize);
        result.setCurrent(pageNum);
        result.setPages(total / pageSize + 1);

        return Response.success(result);
    }

    @Override
    public Response<ReportDetail> getReportDetail(String reportId) {
        // 获取报告下所有的文件
        LambdaQueryWrapper<FileEntity> fileWrapper = Wrappers.<FileEntity>lambdaQuery().eq(FileEntity::getReportId, reportId);
        List<FileEntity> fileEntityList = fileEntityService.list(fileWrapper);
        // 获取所有规则
        List<Rule> ruleList = ruleService.list();
        Map<Integer, Rule> ruleMap = ruleList.stream().collect(Collectors.toMap(Rule::getRuleId, rule -> rule));

        List<Defect> totalDefectList = new ArrayList<>();
        List<FileDefect> fileDefectList = new ArrayList<>();

        for (FileEntity fileEntity : fileEntityList) {
            FileDefect fileDefect = new FileDefect();

            LambdaQueryWrapper<FileRule> fileRuleWrapper = Wrappers.<FileRule>lambdaQuery().eq(FileRule::getFileId, fileEntity.getFileId());
            List<FileRule> fileRuleList = fileRuleService.list(fileRuleWrapper);

            Map<Integer, FileRule> fileRuleMap = fileRuleList.stream().collect(Collectors.toMap(FileRule::getFileRuleId, fileRule -> fileRule));

            List<Integer> ids = fileRuleList.stream().map(FileRule::getFileRuleId).collect(Collectors.toList());
            LambdaQueryWrapper<Defect> defectWrapper = Wrappers.<Defect>lambdaQuery().in(true, Defect::getFileRuleId, ids);
            List<Defect> defectList = defectService.list(defectWrapper);
            totalDefectList.addAll(defectList);

            Map<Integer, List<FileRule>> rule2FileRule = fileRuleList.stream().collect(Collectors.groupingBy(FileRule::getRuleId));
            Map<Integer, List<Defect>> rule2Defect = new HashMap<>();
            for (Integer ruleId : rule2FileRule.keySet()) {
                List<Defect> defects = defectList.stream()
                        .filter(defect -> rule2FileRule.get(ruleId).stream().anyMatch(fileRule -> fileRule.getFileRuleId()==defect.getFileRuleId()))
                        .collect(Collectors.toList());
                rule2Defect.put(ruleId, defects);
            }

            List<RuleDefect> ruleDefectList = new ArrayList<>();
            for (Integer ruleId : rule2Defect.keySet()) {
                RuleDefect ruleDefect = new RuleDefect();
                ruleDefect.setRuleName(ruleMap.get(ruleId).getRuleName());
                ruleDefect.setDefectCount(rule2Defect.get(ruleId).size());
                ruleDefect.setRuleDefectList(convertToDefectVo(rule2Defect.get(ruleId), ruleMap, fileRuleMap));
                ruleDefectList.add(ruleDefect);
            }

            fileDefect.setFileName(fileEntity.getFileName());
            fileDefect.setRuleCount(rule2Defect.size());
            fileDefect.setRuleDefectList(ruleDefectList);

            fileDefectList.add(fileDefect);
        }

        ReportDetail reportDetail = new ReportDetail(fileEntityList.size(), ruleList.size(), totalDefectList.size(), fileDefectList);
        return Response.success(reportDetail);
    }

    private List<DefectVo> convertToDefectVo(List<Defect> defects, Map<Integer, Rule> ruleMap, Map<Integer, FileRule> fileRuleMap) {
        List<DefectVo> result = new ArrayList<>();
        for (Defect defect : defects) {
            int fileRuleId = defect.getFileRuleId();
            FileRule fileRule = fileRuleMap.get(fileRuleId);
            int ruleId = fileRule.getRuleId();

            DefectVo defectVo = new DefectVo(defect.getDefectId(),
                    defect.getProblematicLineNum(),
                    defect.getProblematicSentence(),
                    defect.getReferenceSentence(),
                    ruleMap.get(ruleId).getRuleName(),
                    defect.getReason(),
                    defect.getFixedSentence());
            result.add(defectVo);
        }
        return result;
    }

    private List<ReportVo> convertToReportVo(List<Report> records, String userName) {
        List<ReportVo> result = new ArrayList<>();
        for (Report report : records) {
            ReportVo reportVo = new ReportVo(report.getReportId(), report.getCreateTime(), userName,
                    report.getStatus().getCode());
            reportVo.setUserName(userName);
            result.add(reportVo);
        }

        return result;
    }
}
